/**
 * Copyright (C) 2013 The yydorid-framework project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.yangying.androidframework.util;


import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Observable;
import java.util.Observer;

import android.net.Uri;

public class RemoteResourceManager extends Observable {
    private static final String TAG = "RemoteResourceManager";

    private DiskCache mDiskCache;
    private RemoteResourceFetcher mRemoteResourceFetcher;
    private FetcherObserver mFetcherObserver = new FetcherObserver();

    public RemoteResourceManager(String cacheName) {
        this(new BaseDiskCache(Constant.SDCARD_CACHE_ROOT, cacheName));
    }

    public RemoteResourceManager(DiskCache cache) {
        mDiskCache = cache;
        mRemoteResourceFetcher = new RemoteResourceFetcher(mDiskCache);
        mRemoteResourceFetcher.addObserver(mFetcherObserver);
    }

    public boolean exists(Uri uri) {
        return mDiskCache.exists(getEncryptionKey(Uri.encode(uri.toString())));
    }

    public void store(Uri uri, InputStream is){
    	mDiskCache.store(getEncryptionKey(Uri.encode(uri.toString())), is);
    }
    
    /**
     * If IOException is thrown, we don't have the resource available.
     */
    public File getFile(Uri uri) {
//        Log.d(TAG, "getInputStream(): " + uri);
        return mDiskCache.getFile(getEncryptionKey(Uri.encode(uri.toString())));
    }

    /**
     * If IOException is thrown, we don't have the resource available.
     */
    public InputStream getInputStream(Uri uri) throws IOException {
//        Log.d(TAG, "getInputStream(): " + uri);
        return mDiskCache.getInputStream(getEncryptionKey(Uri.encode(uri.toString())));
    }

    /**
     * Request a resource be downloaded. Useful to call after a IOException from getInputStream.
     */
    public void request(Uri uri) {
//        Log.d(TAG, "request(): " + uri);
        mRemoteResourceFetcher.fetch(uri, getEncryptionKey(Uri.encode(uri.toString())));
    }
    
    /**
     * Explicitly expire an individual item.
     */
    public void invalidate(Uri uri) {
        mDiskCache.invalidate(Uri.encode(uri.toString()));
    }

    public void shutdown() {
        mRemoteResourceFetcher.shutdown();
        mDiskCache.cleanup();
    }

    public void clear() {
        mRemoteResourceFetcher.shutdown();
        mDiskCache.clear();
    }

    public static abstract class ResourceRequestObserver implements Observer {

        private Uri mRequestUri;

        abstract public void requestReceived(Observable observable, Uri uri);

        public ResourceRequestObserver(Uri requestUri) {
            mRequestUri = requestUri;
        }

        @Override
        public void update(Observable observable, Object data) {
//            Log.d(TAG, "Recieved update: " + data);
            Uri dataUri = (Uri)data;
            if (dataUri == mRequestUri) {
//                Log.d(TAG, "requestReceived: " + dataUri);
                requestReceived(observable, dataUri);
            }
        }
    }
    private String getEncryptionKey(String str)
    {
//    	return str;
    	return MD5Utils.md5(str);
    }

    /**
     * Relay the observed download to this controlling class.
     */
    private class FetcherObserver implements Observer {

        @Override
        public void update(Observable observable, Object data) {
            setChanged();
            notifyObservers(data);
        }
    }
}
